;File name: McBSB0IntSup01.asm
;
;  EECS 452 buffered McBS0 support for the C5510DSK
;
;  Configured for single 16-bit transfers.  Does loop around
;  at 1 MHz rate.  Otherwise is set up for number pair transfers.
;  Presently only half of the number pair is transferred.
;  Limiting factor is shift clock and the FPGA sending number
;  pairs.  Conversion to using number pairs likely will involve
;  only changing the constants programmed into the McBSP0
;  control registers. 
;  
;   
;  07Dec2007 .. initial version .. K.Metzger
;

        .c54cm_off                      ;don't want compatible with c54
        .ARMS_on                        ;enable assembler for ARMS=1
        .CPL_on                         ;enable assembler for CPL=1
        .mmregs                         ;enable mem mapped register names
    
        .asg    0x2800, DRR2_0
        .asg    0x2801, DRR1_0
        .asg    0x2802, DXR2_0
        .asg    0x2803, DXR1_0
        .asg    0x2804, SPCR2_0
        .asg    0x2805, SPCR1_0
        .asg    0x2806, RCR2_0
        .asg    0x2807, RCR1_0
        .asg    0x2808, XCR2_0
        .asg    0x2809, XCR1_0
        .asg    0x280A, SRGR2_0
        .asg    0x280B, SRGR1_0
        .asg    0x280C, MCR2_0
        .asg    0x280D, MCR1_0
        .asg    0x2812, PCR_0
        
        .global _McBSP0_Open, _Reset
        .global _McBSP0_Put, _McBSP0_Get

        ; allocate storage
       
        .data
                        
        .bss    Mc0X_buf_adr,2,1,4     ; aligned
        .bss    Mc0X_app_buf_off,1
        .bss    Mc0X_int_buf_off,1
        .bss    Mc0X_buf_size,1
        .bss    Mc0X_counter,1
        .bss    Mc0X_running_flag,1
        
        .bss    Mc0R_buf_adr,2,1,4     ; aligned
        .bss    Mc0R_app_buf_off,1
        .bss    Mc0R_int_buf_off,1
        .bss    Mc0R_buf_size,1
        .bss    Mc0R_counter,1

        .text
        
        .asg    0001100000000000b,my_ST0_55
        .asg    0110100100000000b,my_ST1_55
        .asg    1001000000000000b,my_ST2_55
        .asg    0001000000000010b,my_ST3_55
                 
            
; Setup McBSP channel 0 codec interrupt support 
;
;  for now assumes setup_McBSP0() has been called
;
          	.align 4
          
_McBSP0_Open:
            mov #0x0000, port(#SPCR1_0) 
            mov #0x0000, port(#SPCR2_0) 
            mov #0x0040, port(#RCR1_0)		; 16-bit value
            mov #0x0000, port(#RCR2_0) 
            mov #0x0040, port(#XCR1_0)		; 16-bit value
            mov #0x0000, port(#XCR2_0) 
            mov #0x0000, port(#SRGR1_0) 
            mov #0x0000, port(#SRGR2_0) 
            mov #0x0000, port(#MCR1_0) 
            mov #0x0000, port(#MCR2_0) 
            mov #0x0000, port(#PCR_0) 
            mov #0x0001, port(#SPCR1_0) 
            mov #0x00C1, port(#SPCR2_0) 
            
            pshboth xar3    ; save c(xar3)
            
            amov    #Mc0R_buf_adr,xar3                     ; setup get support
            mov     xar0,dbl(*ar3)                         ; get the A/D in buffer address address
            mov     T0,*ar3(Mc0R_buf_size-Mc0R_buf_adr)    ; get the L&R pair count
            mov     #0,*ar3(Mc0R_app_buf_off-Mc0R_buf_adr) ; initialize application level buffer offset
            mov     #0,*ar3(Mc0R_int_buf_off-Mc0R_buf_adr) ; initialize interrupt level buffer offset
            mov     #0,*ar3(Mc0R_counter-Mc0R_buf_adr)     ; nothing present yet
            
            amov    #Mc0X_buf_adr,xar3                      ; point to buffer address address
            mov     xar1,dbl(*ar3)                          ; save address of L&R output buffer
            mov     T1,*ar3(Mc0X_buf_size-Mc0X_buf_adr)     ; save number of L&R pairs
            mov     #0,*ar3(Mc0X_app_buf_off-Mc0X_buf_adr)  ; initialize application level offset value
            mov     #0,*ar3(Mc0X_int_buf_off-Mc0X_buf_adr)  ; initialize interrupt level offset value
            mov     #0,*ar3(Mc0X_counter-Mc0X_buf_adr)      ; nothing in the buffer yet
            mov     #0,*ar3(Mc0X_running_flag-Mc0X_buf_adr) ; and the TX is not going to interrupt us yet
            
            ; selecting mode is not yet supported..mode value should be in ar2
              
            mov     #_Reset >> 8, ac0      ; get int vector address page
            mov     ac0,mmap(ivpd)          ; set up DSP int address
            mov     ac0,mmap(ivph)          ; set up host int address
            amov    #Mc0R_int,xar3          ; set up McB port 0 rcvr addr 
            mov     xar3,dbl(*((_Reset+0x28)/2))
            amov    #Mc0X_int,xar3          ; set up McB port 0 xmtr addr
            mov     xar3,dbl(*((_Reset+0x88)/2))
            or      #0x0020,mmap(ifr0)      ; clear Mc0 rcvr interrupt flag
            or      #0x0002,mmap(ifr1)      ; clear Mc0 xmtr interrupt flag
            or      #0x0020,mmap(ier0)      ; enable Mc0RX interrupt
            or      #0x0002,mmap(ier1)      ; enable Mc0TX interrupt         
            popboth xar3                    ; restore c(xar3)
            ret

                
; Support for McBSB0 interrupt driven data transfers (max 40 (?) clock tics)

            .align 4

Mc0R_int:   
            psh     mmap(st3_55)
            psh     mmap(T0)
            psh     mmap(T1)
            pshboth xar0
            pshboth xar1 
            mov     #my_ST0_55,mmap(st0_55) ; now configure the machine
            mov     #my_ST1_55,mmap(st1_55)
            mov     #my_ST2_55,mmap(st2_55)
            mov     #my_ST3_55,mmap(st3_55)

            amov    #Mc0R_buf_adr,xar1      ; get buffer address address
            mov     *ar1(Mc0R_counter-Mc0R_buf_adr),T0      ; get # L&R values in buffer
            mov     *ar1(Mc0R_buf_size-Mc0R_buf_adr),T1     ; get number allowed
            cmp     T0==T1,TC1              ; if equal full
            bcc     R0I_LA,!TC1             ; branch if room
            mov     port(#DRR1_0),T0        ; clears the receive interrupt flag
            b       Mc0R_exit               ; and exits...samples are discarded
R0I_LA:
            mov     dbl(*ar1), xar0         ; get buffer address
            add     *ar1(Mc0R_int_buf_off-Mc0R_buf_adr),ar0 ; and calculate where to place values
            add     *ar1(Mc0R_int_buf_off-Mc0R_buf_adr),ar0 ; pairs of values
            mov     port(#DRR2_0),T0        ; get left value
            mov     T0,*ar0+                ; and place into buffer
            mov     port(#DRR1_0),T0        ; get right value...and clear flag
            mov     T0,*ar0                 ; place into buffer
            add     #1,*ar1(Mc0R_counter-Mc0R_buf_adr)      ; increment count of pairs present
            mov     *ar1(Mc0R_int_buf_off-Mc0R_buf_adr),T0  ; now update offset circularly
            add     #1,T0                   ; increment
            cmp     T0==T1,TC1              ; see if needs to be reset to buffer start
            bcc     R0I_LB,!TC1             ; branch if not
            mov     #0,T0                   ; reset to buffer start
R0I_LB:
            mov     T0,*ar1(Mc0R_int_buf_off-Mc0R_buf_adr)  ; and update in memory
Mc0R_exit:         
            popboth xar1            
            popboth xar0
            pop     mmap(T1)
            pop     mmap(T0)
            pop     mmap(st3_55)
            nop                             ; 6 nops stops remarks 99 and 100
            nop
            nop
            nop
            nop
            nop
            reti

; Support to fetch codec sample values L&R pair  (max 23 (?) clock tics)       
            
            .align 4
            
_McBSP0_Get:   
            pshboth xar2                    ; use it, save it
            pshboth xar3                    ; use it, save it
            amov    #Mc0R_buf_adr,xar3      ; get in sample buffer address address
Mc0R_wait:            
            mov     *ar3(Mc0R_counter-Mc0R_buf_adr),T0 ; get count of pairs in buffer
            bcc     Mc0R_wait,T0==#0        ; wait if there aren't any
            mov     dbl(*ar3),xar2          ; set up buffer address
            add     *ar3(Mc0R_app_buf_off-Mc0R_buf_adr),ar2 ; we are working with pairs
            add     *ar3(Mc0R_app_buf_off-Mc0R_buf_adr),ar2
            mov     *ar2+,T0                ; fetch L value
            mov     T0,*ar0                 ; and place in caller's location
            mov     *ar2,T0                 ; fetch R value
            mov     T0,*ar1                 ; and place in caller's location
            sub     #1,*ar3(Mc0R_counter-Mc0R_buf_adr)      ; indivisible decrement of count
            mov     *ar3(Mc0R_app_buf_off-Mc0R_buf_adr),T0  ; now update offset circularly
            add     #1,T0                   ; increment
            mov     *ar3(Mc0R_buf_size-Mc0R_buf_adr),T1     ; get limiting value
            cmp     T0==T1,TC1              ; if equal need to reset to 0
            bcc     R0_LA,!TC1              ; branch if not equal
            mov     #0,T0                   ; zero to start of buffer
R0_LA:
            mov     T0,*ar3(Mc0R_app_buf_off-Mc0R_buf_adr)  ; and update in memory 
            popboth xar3 
            popboth xar2
            ret
           
;---------------------------------------------------------------------------------------
;
;   Support to send L&R sample values to the AIC23 codec (max 42 (?) clock tics)
            
            .align 4
            
Mc0X_int:   
            psh     mmap(st3_55)
            psh     mmap(T0)
            psh     mmap(T1)
            pshboth xar0
            pshboth xar1
            mov     #my_ST0_55,mmap(st0_55) ; now configure the machine
            mov     #my_ST1_55,mmap(st1_55)
            mov     #my_ST2_55,mmap(st2_55)
            mov     #my_ST3_55,mmap(st3_55)

			amov    #Mc0X_buf_adr,xar1      ; get TX buffer address address
			mov     dbl(*ar1),xar0          ; get TX buffer address
            mov     *ar1(Mc0X_counter-Mc0X_buf_adr),T0  ; get count of pairs pesent in buffer
            bcc     X0I_LA,T0==0            ; if none nothing to do
            sub     #1,*ar1(Mc0X_counter-Mc0X_buf_adr) ; we will send a LR pair reducing the count
            add     *ar1(Mc0X_int_buf_off-Mc0X_buf_adr),ar0 ; and add in offset
            add     *ar1(Mc0X_int_buf_off-Mc0X_buf_adr),ar0 ; count is in pairs
            mov     *ar0+,T0                ; get L value from buffer
            mov     T0,port(#DXR2_0)        ; and send to L in TX
            mov     *ar0,T0                 ; get R value from buffer
            mov     T0,port(#DXR1_0)        ; and send to R in TX and clear flag
            mov     #1,*ar1(Mc0X_running_flag-Mc0X_buf_adr) ; note we expecting an interrupt
            mov     *ar1(Mc0X_int_buf_off-Mc0X_buf_adr),T0  ; now need to up interrupt buffer offset
            add     #1,T0                   ; circularly
            mov     *ar1(Mc0X_buf_size-Mc0X_buf_adr),T1     ; compare offset with buffer size
            cmp     T0==T1,TC1              ; if equal need to reset to 0
            bcc     X0I_LB,!TC1             ; branch if not needed to reset to 0
            mov     #0,T0                   ; get the zero
X0I_LB:     
            mov     T0,*ar1(Mc0X_int_buf_off-Mc0X_buf_adr)  ; and update the value in memory
            b       X0I_exit                ; all done so exit
X0I_LA:     
            mov     #0,*ar1(Mc0X_running_flag-Mc0X_buf_adr) ; note we are not expecting an interrupt                    
X0I_exit:           
            popboth xar1
            popboth xar0
            pop     mmap(T1)
            pop     mmap(T0)
            pop     mmap(st3_55)
            nop                             ; 6 nops stop remarks 99 and 100
            nop
            nop
            nop
            nop
            nop
            reti
            
    
; Application level function to send L&R values to DAC   (max 25 (?) clock tics)        
;           
; 32 bit value in AC0 left in high right in low

			.align 4

_McBSP0_Put:  
            mov     T0,mmap(ac0h)           ; save left value
            mov     T1,mmap(ac0l)           ; save right value
XL0_LC:         
            amov    #Mc0X_buf_adr,xar1      ; point to buffer address address
            mov     *ar1(Mc0X_counter-Mc0X_buf_adr),T0  ; number values present
            mov     *ar1(Mc0X_buf_size-Mc0X_buf_adr),T1 ; number of spaces available
            cmp     T0==T1,TC1              ; see if they are equal
            bcc     XL0_LC,TC1              ; wait if no room
            mov     dbl(*ar1),xar0          ; get buffer address
            add     *ar1(Mc0X_app_buf_off-Mc0X_buf_adr),ar0
            add     *ar1(Mc0X_app_buf_off-Mc0X_buf_adr),ar0 ; two word offset needed
            mov     HI(ac0),*ar0+           ; store left value into buffer
            mov     ac0,*ar0                ; store right value into buffer
            bset    intm                    ; disable interrupts
            add     #1,*ar1(Mc0X_counter-Mc0X_buf_adr) ; increment count
            mov     *ar1(Mc0X_running_flag-Mc0X_buf_adr),T0
            bcc     X0_LA,T0!=0             ; branch if xmtr running
            intr    #0x11                   ; throw the software trap if not
X0_LA:      
            bclr    intm                    ; reenable interrupts
            mov     *ar1(Mc0X_app_buf_off-Mc0X_buf_adr),T0; ; now update buffer offset
            add     #1,T0                   ; increment 
            cmp     T0==T1,TC1              ; may need to reset
            bcc     X0_LB,!TC1              ; not yet
            mov     #0,T0                   ; put back to buffer start
X0_LB:
            mov     T0,*ar1(Mc0X_app_buf_off-Mc0X_buf_adr) ; update the putting offset             
X0_exit:            
            ret
                        
            